/*
 * Hy103Client.h
 *
 *  Created on: Dec 7, 2011
 *      Author: kylintse
 */

#ifndef HY103CLIENT_H_
#define HY103CLIENT_H_

#include <QtNetwork>

#include "gtype.h"
#include "gdata.h"
#include "KjDevice.h"
#include "klog.h"
#include "kthread.h"

class Hy103ClientParser;
class Hy103ClientMaker;
class Hy103ClientSender;
class Hy103ClientEventProcessor;

enum Hy103ServerType
{
	hstScs=1,
	hstRtu=2,
	hstDebug=3,
	hstPrt=4,
	hstSac=5,
};

typedef struct _tHy103Server
{
	bool connected;
	quint32 ip;
	int sockfd;
	Hy103ServerType type;
	Hy103ClientParser* parser;
	Hy103ClientMaker* maker;
	Hy103ClientSender* sender;
	Hy103ClientEventProcessor* eventProcessor;
	KjDeviceList* lstDevice;
	QMutex lock;
	QString interface;
	QDateTime heartBeatTime;
	QMutex lockDatagram;
	QSemaphore* semDatagram;
	QQueue<QByteArray> datagrams;
}Hy103Server;

enum ASDU_TYPE_VAL
{
    ASDU_1 = 0x01,
    ASDU_6 = 0x06,
    ASDU_5 = 0x05,
    ASDU_7 = 0x07,
    ASDU_10 = 0x0A,
    ASDU_20 = 0x14,
    ASDU_21 = 0x15,
    ASDU_23 = 0x17,
    ASDU_24 = 0x18,
    ASDU_25 = 0x19,
    ASDU_26 = 0x1A,
    ASDU_27 = 0x1B,
    ASDU_28 = 0x1C,
    ASDU_29 = 0x1D,
    ASDU_30 = 0x1E,
    ASDU_31 = 0x1F,
    DEB_SW = 0x68,
};

enum ASDU_LENGTH_VAL
{
    ASDU_5_LENGTH = 0x13,
    ASDU_6_LENGTH = 0x0D,
    ASDU_7_LENGTH = 0x07,
    ASDU_20_LENGTH = 0x08,
    ASDU_21_LENGTH = 0x0B,
    ASDU_21_FIX_LENGTH = 0x08,
    ASDU_24_LENGTH = 0x0B,
    ASDU_25_LENGTH = 0x0B,
};

enum ASDU_FRAME_INDEX
{
    ASDU_TYP_INDEX = 0,
    ASDU_VSQ_INDEX = 0x01,
    ASDU_COT_INDEX = 0x02,
    ASDU_CPU_INDEX = 0x03,
    ASDU_FUN_INDEX = 0x04,
    ASDU_INF_INDEX = 0x05,
    ASDU_RII_INDEX = 0x06,
    ASDU_NOG_INDEX = 0x07,
};

enum FUN_TYPE
{
    FUN_GEN = 0xFE,
    FUN_GLB = 0xFF,
};

enum DEVIVE_INF_TYPE
{
    INF_READ_GRP_TITLE = 0xF0,  /*240*/
    INF_READ_ALL_VAL = 0xF1,    /*241*/
    INF_READ_SINGLE_VAL = 0xF4, /*244*/
    INF_CONFIRM_WRITE = 0xF9,   /*249*/
    INF_EXECUTE_WRITE = 0xFA,   /*250*/
};

enum COT_OF_CONTROL
{
    COT_SYN_TM = 0x08,
    COT_GI = 0x09,
    COT_GRC = 0x14,
    COT_DDT = 0x1F,
    COT_GEN_WRITE = 0x28,
    COT_GEN_READ = 0x2A,
};

enum COT_OF_DEVICE
{
    COT_AUTOSEND = 0x01,
    COT_REPEAT = 0x02,
    COT_RESET_FCB = 0x03,
    COT_WAVE_SEND = 0x1F,
    COT_WRITE_OK = 0x28,
    COT_WRITE_ERR = 0x29,
    COT_READ_OK = 0x2A,
    COT_READ_ERR = 0x2B,
    COT_WRITE_CONFIRM = 0x2C,
};

enum VSQ_VAL
{
    VSQ_COMM = 0x81,    /*Common VSQ*/
};

enum KOD_TYPE
{
    KOD_ACTUAL_VAL = 0x01,
    KOD_DEF_VAL = 0x02,
    KOD_RANGE = 0x03,
    KOD_PRECISION = 0x05,
    KOD_FACTOR = 0x06,
    KOD_DIMENSION = 0x09,
    KOD_DESC = 0x0a,
};

enum GDD_DATATYPE
{
    DATATYPE_NULL = 0x00,
    DATATYPE_OS8 = 0x01,
    DATATYPE_BS1 = 0x02,
    DATATYPE_UI = 0x03,
    DATATYPE_I = 0x04,
    DATATYPE_UF = 0x05,
    DATATYPE_F = 0x06,
    DATATYPE_R3223 = 0x07,
    DATATYPE_R6453 = 0x08,
    DATATYPE_DPI = 0x09,
    DATATYPE_SPI = 0x0a,
    DATATYPE_CHARACT=0x0c,
    DATATYPE_TM_DPI = 0x12,
    DATATYPE_STRUCT = 0x17,
};

enum GDD_DPI_VAL
{
    DPI_ON = 0x02,
    DPI_OFF = 0x01,
};

enum GDD_DATATYPE_LENGTH
{
    DATATYPE_R3223_LEN = 0x04,
    DATATYPE_TM_DPI_LEN = 0x06,
};

/*Group of Lan 103*/
enum LAN103_GROUP
{
    LAN_GRP_SYS = 0x00,
    LAN_GRP_SET = 0x03,
    LAN_GRP_EVT = 0x04,
    LAN_GRP_ALM = 0x05, /*Alarm*/
    LAN_GRP_PROTECT_MEA = 0x06, /*Anolog value*/
    LAN_GRP_REMOTE_MEA=0x07,
    LAN_GRP_SOE_DI  = 0x08,
    LAN_GRP_NO_SOE_DI  = 0x09,
    LAN_GRP_PULSE=0x0A,
    LAN_GRP_VDI = 0x0E,
    LAN_GRP_WAV_AC = 0x10,  /*AC channel description of wave*/
    LAN_GRP_WAV_DI = 0x11,  /*DI channel description of wave*/
    LAN_GRP_SOE_TM = 0x18,
    LAN_GRP_EVT_ARG = 0x19, /*Event argument*/
    LAN_GRP_MEA_CTR_PARA=0x21,
};

/*Ethernet 103 Setting Group Number*/
enum LAN103_SET_GRP_Number
{
    LAN_SET_GRP_0 = 0x02,
    LAN_SET_GRP_1 = 0x03,
    LAN_SET_GRP_EXT_0 = 0x30,
    LAN_SET_GRP_EXT_1 = 0x31,
    LAN_SET_GRP_EXT_2 = 0x32,
    LAN_SET_GRP_EXT_3 = 0x33,
    LAN_SET_GRP_EXT_4 = 0x34,
    LAN_SET_GRP_EXT_5 = 0x35,
    LAN_SET_GRP_EXT_6 = 0x36,
    LAN_SET_GRP_EXT_7 = 0x37,
    LAN_SET_GRP_EXT_8 = 0x38,
};

/*Item number of system Group in lan 103*/
enum LAN103_SYS_GRP_ITEM
{
    LAN_SYS_OPERATE_SETZONE = 0x02,
    LAN_SYS_RUN_SETZONE = 0x03,
    LAN_SYS_RESET = 0x06,
};

/*Attribes about 04 board, send in 8400H*/
#define     FTYPE_EVT_PRINT     0x01
enum EVENT_TYPE_VAL
{
    EVT_EVENT = 0x01,
    EVT_CPU_ALM = 0x02,
};


enum GEN_DATA_SET_INDEX
{
    GEN_GIN_GRP = 0x00,
    GEN_GIN_ITEM = 0x01,
    GEN_KOD = 0x02,
    GEN_GDD_TYPE = 0x03,
    GEN_GDD_SIZE = 0x04,
    GEN_GDD_NUMBER = 0x05,
};

/*type of setting and internal setting*/
enum SET_TYPE_VAL
{
    SET_TYP_CTL_WORD = 0x00,
    SET_TYP_FAULT_PHASE = 0x40,
    SET_TYP_UI_16 = 0x60,
    SET_TYP_UI_32 = 0x61,
    SET_TYP_CTL_WORD_32 = 0x6B,
};
enum SET_TYPE_VAL_LENGTH
{
    SET_TYP_CTL_WORD_LEN = 0x01,
//    SET_TYP_CTL_WORD_LEN = 0x02,

    SET_TYP_FAULT_PHASE_LEN = 0x01,
    SET_TYP_UI_16_LEN = 0x02,
    SET_TYP_UI_32_LEN = 0x04,
    SET_TYP_CTL_WORD_32_LEN = 0x04,
    SET_TYP_FLOAT_LEN = 0x04,
};
enum SET_TYPE_VAL_PREC   /*setting value precision*/
{
    SET_TYP_CTL_WORD_PREC_L = 0x02,
    SET_TYP_CTL_WORD_PREC_H = 0x00,
    SET_TYP_FAULT_PHASE_PREC_L = 0x02,
    SET_TYP_FAULT_PHASE_PREC_H = 0x00,
    SET_TYP_UI_16_PREC_L = 0x05,
    SET_TYP_UI_16_PREC_H = 0x00,
    SET_TYP_UI_32_PREC_L = 0x0A,
    SET_TYP_UI_32_PREC_H = 0x00,
    SET_TYP_CTL_WORD_32_PREC_L = 0x0A,
    SET_TYP_CTL_WORD_32_PREC_H = 0x00,
    SET_TYP_FLOAT_PREC_L = 0x03,
    SET_TYP_FLOAT_PREC_H = 0x03,
};

enum WAVE_SEND_TOO_VAL
{
    WAV_SEND_TOO_SELECT_WAVE = 1,       /*select wave*/
    WAV_SEND_TOO_REQ_FAULT_DATA = 2,    /*Require fault data*/
    WAV_SEND_TOO_REQ_CHANNEL_DATA = 8,  /*Require analog channel data*/
    WAV_SEND_TOO_REQ_FAULT_TAB = 24,    /*Require fault table*/
    WAV_SEND_TOO_REQ_DI_CHG_INFO = 16,  /*Require di change information*/

    WAV_SEND_TOO_COMFIRM_DI_SEND = 68,  /*di send ok*/

    WAV_SEND_TOO_DEV_STOP_WAV_SEND = 34,    /*device stop wave data send*/
    WAV_SEND_TOO_DEV_STOP_CHANNEL_SEND = 37,/*device stop wave channel data send*/
    WAV_SEND_TOO_DI_SEND_FINISH = 38,   /*di change information send ok*/
    WAV_SEND_TOO_DEV_STOP_DI_SEND = 40, /*device stop send di actively*/
};

enum WAV_SEND_FLAG
{
    WAV_SEND_FLAG_NULL = 0x00,   /*invalid state*/
    WAV_SEND_FLAG_WAV_READY = 0x01,     /*send wave ready*/
    WAV_DI_SEND_FLAG_SEND_INIT = 0x02,  /*send di initial state*/
    WAV_DI_SEND_FLAG_SEND_CHG = 0x03,   /*send change information*/
    WAV_DI_SEND_FLAG_SEND_CHG_FIN = 0x04,   /*send di change ok*/
};

#define HY103_MAX_FRAME_LEN 1460
#define HY103_MIN_FRAME_LEN	7

class Hy103ClientParser : public kthread
{
	Q_OBJECT
public:
	Hy103ClientParser(Hy103Server* server,QObject* parent=0);
	virtual ~Hy103ClientParser();

public:
	quint32 serverIp(){return m_server->ip;}

signals:
//	void sigRemoteClose(quint32 ip);

protected:
	virtual void run();

	bool headValid(qint32& len);
	qint32 analyzeDatagramLen(qint32 curLen,qint32& itemHeadPos,qint32 wantLen,
			qint32& itemNum);
	qint32 calcAsdu10Len(qint32 curLen,qint32& itemHeadPos,qint32 wantLen,
			qint32& itemNum);
	qint32 calcAsdu21Len(qint32 curLen,qint32& itemHeadPos,qint32 wantLen,
			qint32& itemNum);

	void processFrame(qint32 frameLen);

	void processFrameLocal(quint32 frameLen);

private:
	void processFrameAsdu10(quint32 frameLen);
	void processFrameAsdu20(quint32 frameLen);
	void processFrameAsdu21(quint32 frameLen);

	void processFrameReadAllItemInGrp(quint32 frameLen);

	void processFrameReadValue(quint32 frameLen);
	void processFrameReadDesc(quint32 frameLen);
	void processFrameReadRange(quint32 frameLen);
	void processFrameReadPrecision(quint32 frameLen);
	void processFrameReadDimension(quint32 frameLen);

	void processFrameReadDevDesc(quint32 frameLen);
	void processFrameReadChnnlCoff(quint32 frameLen);
	void processFrameWriteChnnlCoff(quint32 frameLen);
	void processFrameSaveChnnlCoff(quint32 frameLen);

	void sendReply(QByteArray& data);

private:
	Hy103Server* m_server;
	char m_recvBuf[HY103_MAX_FRAME_LEN];
	QString m_source;
	quint32 m_ethId;
};

class Hy103ClientMaker : public kthread
{
	Q_OBJECT
public:
	Hy103ClientMaker(Hy103Server* server,QObject* parent=0);
	virtual ~Hy103ClientMaker();

protected:
	virtual void run();

protected :
	void makeAiTransmit();
	void makeDiTransmit();
	void makePiTransmit();

private:
	Hy103Server* m_server;
	quint8 m_rii;
};

class Hy103ClientSender : public kthread
{
public:
	Hy103ClientSender(Hy103Server* server,QObject* parent=0);
	virtual ~Hy103ClientSender();

protected:
	virtual void run();

private:
	Hy103Server* m_server;
};

class Hy103ClientEventProcessor : public kthread
{
public:
	Hy103ClientEventProcessor(Hy103Server* server,QObject* parent=0);
	virtual ~Hy103ClientEventProcessor();

protected:
	virtual void run();

private:
	Hy103Server* m_server;
	quint32 m_id;
	QString m_processorId;
};

class MprDatagramProcessor : public kthread
{
public:
	MprDatagramProcessor(KjDeviceList* lstDevice,QObject* parent=0);
	virtual ~MprDatagramProcessor();

public:
	bool registerHy103Sender(const QString& interface,Hy103Server* server);
	bool unRegisterHy103Sender(const QString& interface,quint32 ip);

protected:
	virtual void run();

private:
	KjDeviceList* m_lstDevice;

	QMutex m_lockSender;
	QList<Hy103Server*> m_lstSenderEth0;
	QList<Hy103Server*> m_lstSenderEth1;
};

#define UDP_PORT_ETH0			1032
#define UDP_PORT_ETH1			1033
#define TCP_PORT_ETH0			1048
#define TCP_PORT_ETH1			1049

#define HEARTBEAT_TIMEOUT		30

class Hy103Client : public QObject
{
	Q_OBJECT
public:
	Hy103Client(const QString& interface,KjDeviceList* lstDevice,
			MprDatagramProcessor* dgProcessor);
	virtual ~Hy103Client();

public:
	bool init();
	void close();

protected slots:
	void processUdpData();
	void timerCheckHeartBeat();
	void remoteClose();

protected:
	void adjustTime(const QByteArray& data);
	void closeServer(quint32 ip);

private:
	bool m_bRunning;
	QString m_interface;
	QString m_localIp;
	quint16 m_udpPort;
	quint16 m_tcpPort;

	QUdpSocket* m_udpSocket;

	QMutex m_lockServers;
	QMap<quint32,Hy103Server*> m_servers;

	QTimer* m_timerHeartBeat;

	KjDeviceList* m_lstDevice;
	MprDatagramProcessor* m_dgProcessor;

	qint32 m_watchDogId;
};

class Hy103ClientManager : public kthread
{
	Q_OBJECT
public:
	Hy103ClientManager(const QString& interface,KjDeviceList* lstDevice,
			MprDatagramProcessor* dgProcessor,QObject* parent=0);
	virtual ~Hy103ClientManager();

protected:
	virtual void run();

private:
	Hy103Client* m_client;
	QString m_interface;

	KjDeviceList* m_lstDevice;
	MprDatagramProcessor* m_dgProcessor;
};

#endif /* HY103CLIENT_H_ */
